package com.qf.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

/**
 *
 * 推送报告监听器
 * @author YDW
 * projectName:project2202_4
 * time:2022/6/21 21:37
 * description:
 */
@Configuration
@Slf4j
public class PushReportListener {

    @Autowired
    CacheFeign cacheFeign;

    @Autowired
    RabbitTemplate template;

    //第一次推送，消费消息
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void consum(StandardReport report, Channel channel, Message message){
        //1.获取客户端id
        long clientID = report.getClientID();

        //2.获取client对象
        Map<String,String> map = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);

        //3.获取receivestatusurl(回调地址)，
        String receivestatusurl = map.get("receivestatusurl");

        //4.获取isreturnstatus的值，如果为1，则推送报告给客户端（回调）
        String isreturnstatus = map.get("isreturnstatus");
        if("1".equalsIgnoreCase(isreturnstatus)){
            //4.1 发送报告判断是否发送成功，如果发送成功则手动ack，
            //设置第一次发送
            report.setSendCount(1);
            //设置回调url地址
            report.setReceiveStatusUrl(receivestatusurl);
            //发送报告
            String result= null;
            try {
                result = sendReport(report);
            } catch (Exception e) {
                e.printStackTrace();
            }

            //4.2 确认结果
            isSuccess(report,result,channel,message);


        }else {//如果为0，则不推送报告（不回调）
            //在控制台记录日志
            log.info("[接口模块 -- 报告推送] 客户端不需要推送报告！！ report={}",report);
            //手动ack（手动确认消息）
            try {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


    }

    @Autowired
    RestTemplate restTemplate;

    //发送报告给客户端（千锋互联）
    private String sendReport(StandardReport report) {
        //回调url地址
        String url = report.getReceiveStatusUrl();
        //请求头
        HttpHeaders httpHeaders=new HttpHeaders();
        //请求体数据类型
        httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);

        //把report对象转换为json
        ObjectMapper mapper=new ObjectMapper();
        String json=null;
        try {
            json = mapper.writeValueAsString(report);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        /*
        * 参数1 ： body为请求体数据
        * 参数2 ： header  请求头
        * */
        HttpEntity httpEntity=new HttpEntity(json,httpHeaders);


        /*
        * 参数1：url对象
        * 参数2：请求头对象
        * 参数3：返回值类型
        *
        * */


        ResponseEntity<String> responseEntity=restTemplate.postForEntity(url,httpEntity,String.class);
        //body是方法的返回值
        return responseEntity.getBody();

    }

    private static final int[] ttl=new int[]{0,10000,30000,120000,300000};
    //如果发送失败，把消息发送到延时队列，手动ack,如果成功手动ack
    private void isSuccess(StandardReport report, String result, Channel channel, Message message) {


        //如果回调的结果为success，则认为发送报告成功
        if("success".equalsIgnoreCase(result)){
            log.info("[接口模块 -- 发送报告] 发送报告成功！ report={}",report);
        }else{//否则，发送报告失败，推送消息到延时队列
            log.info("[接口模块 -- 发送报告] 第 {} 次发送报告失败！ report={}",report.getSendCount(),report);

            //发送消息到延时队列
            //最多发送五次
            if(report.getSendCount()<=4){
                //设置发送次数
                report.setSendCount(report.getSendCount()+1);
                //参数4： 消息的后处理对象
                template.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "routingKey", report, new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) throws AmqpException {
                        //设置延时时间
                        message.getMessageProperties().setDelay(ttl[report.getSendCount()-1]);
                        return message;
                    }
                });
            }



        }

        //无论成功与否，需要手动ack
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /*
    * 处理延时队列的消息（除第一个发送报告，都要走此方法）
    * */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void consumDelay(StandardReport report,Channel channel,Message message){
        String result = null;
        try {
            result = this.sendReport(report);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //处理结果
        isSuccess(report,result,channel,message);
    }


}
